package com.derbysoft.synxisadapter.commons.repository.impl;

import com.derbysoft.core.CriteriaCreator;
import com.derbysoft.core.Limit;
import com.derbysoft.core.LimitedList;
import com.derbysoft.core.Sorter;
import com.derbysoft.synxisadapter.commons.model.Channel;
import com.derbysoft.synxisadapter.commons.model.TaxPolicy;
import com.derbysoft.synxisadapter.commons.repository.ChannelRepository;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;

public class ChannelRepositoryImpl extends BaseRepositorySupport implements ChannelRepository {

    @Override
    @Transactional(readOnly = false)
    public void save(Channel channel) {
        dataAccessor.save(channel);
    }

    @Override
    @Transactional(readOnly = false)
    public void delete(Channel channel) {
        dataAccessor.delete(channel);
    }

    @Override
    public Channel findByCode(final String channelCode) {
        return dataAccessor.findUnique(Channel.class, new CriteriaCreator() {
            @Override
            public Criteria createCriteria(Session session) {
                Criteria criteria = session.createCriteria(Channel.class);
                criteria.add(Restrictions.eq("code", channelCode));

                return criteria;
            }
        });
    }

    @Override
    public Channel findByPassport(final String passport) {
        return dataAccessor.findUnique(Channel.class, new CriteriaCreator() {
            @Override
            public Criteria createCriteria(Session session) {
                Criteria criteria = session.createCriteria(Channel.class);
                criteria.add(Restrictions.eq("passport", passport));

                return criteria;
            }
        });
    }

    @Override
    public LimitedList<Channel> findByCondition(final ChannelCondition condition, Limit limit) {
        return dataAccessor.findByCriteria(Channel.class, new CriteriaCreator() {
            @Override
            public Criteria createCriteria(Session session) {
                Criteria criteria = session.createCriteria(Channel.class);
                if (condition != null) {
                    populateCriteria(criteria, condition);
                }
                return criteria;
            }
        }, limit, new Sorter().desc("id"));
    }

    @Transactional
    @Override
    public void update(String passport, String name, String id, String code, String iataNumber, String userName, String password,
                       TaxPolicy taxPolicy, boolean inclusiveTaxRate) {
        Channel channel = findByPassport(passport);
        if (channel == null) {
            throw new IllegalArgumentException(String.format("passport [%s] not found.", passport));
        }

        channel.setName(name);
        channel.setId(id);
        channel.setCode(code);
        channel.setIataNumber(iataNumber);
        channel.setUserName(userName);
        channel.setPassword(password);
        channel.setTaxPolicy(taxPolicy);
        channel.setInclusiveTaxRate(inclusiveTaxRate);
        dataAccessor.update(channel);
    }

    @Transactional
    @Override
    public void create(String passport, String name, String id, String code, String iataNumber, String userName, String password,
                       TaxPolicy taxPolicy, boolean inclusiveTaxRate) {
        if (findByPassport(passport) != null) {
            throw new IllegalArgumentException(String.format("passport [%s] already in use.", passport));
        }

        Channel channel = new Channel();

        channel.setPassport(passport);
        channel.setName(name);
        channel.setId(id);
        channel.setCode(code);
        channel.setIataNumber(iataNumber);
        channel.setUserName(userName);
        channel.setPassword(password);
        channel.setTaxPolicy(taxPolicy);
        channel.setInclusiveTaxRate(inclusiveTaxRate);
        dataAccessor.save(channel);
    }

    private void populateCriteria(Criteria criteria, ChannelCondition condition) {
        if (StringUtils.isNotBlank(condition.getPassport())) {
            criteria.add(Restrictions.ilike("passport", condition.getPassport(), MatchMode.ANYWHERE));
        }

        if (StringUtils.isNotBlank(condition.getName())) {
            criteria.add(Restrictions.ilike("name", condition.getName(), MatchMode.ANYWHERE));
        }

        if (StringUtils.isNotBlank(condition.getId())) {
            criteria.add(Restrictions.eq("id", condition.getId()));
        }

        if (StringUtils.isNotBlank(condition.getCode())) {
            criteria.add(Restrictions.eq("code", condition.getCode()));
        }
        if (StringUtils.isNotBlank(condition.getInclusiveTaxRate())) {
            criteria.add(Restrictions.eq("inclusiveTaxRate", StringUtils.equals(condition.getInclusiveTaxRate(), "Y")));
        }
        if (condition.getTaxPolicy() != null) {
            criteria.add(Restrictions.eq("taxPolicy", condition.getTaxPolicy()));
        }
    }
}